/* 算法实现模板 */
import Perceptron from "./Perceptron";
import Vector, { calGramMatrix } from "../../common/Vector";
import { showMathStringInTable } from "../../visual/Table2D";

import DefautValue from "./input/DualFormPerceptron.input.json";

class DualFormPerceptron extends Perceptron{
  constructor(){
    super();
    this.id = 'DualFormPerceptron';    
  }

  init(){
    this.loadModel(DefautValue);

    if(this.domFigure) {
      this.domFigure.innerHTML = '';
      this.domFigure.appendChild(this.figure.domElement);
    }
    this.print();
  }

  // 训练
  train(){
    const Tx = this.trainDS.x;
    const Ty = this.trainDS.y;
    var alpha = new Vector(Tx.length, true);
    var b = 0.0;
    var eta = parseFloat(this.model.eta);

    var count = 0;
    var isDone = false;

    const G = calGramMatrix(Tx);

    var trainLog = [];    // 训练日志
    trainLog.push([]);
    trainLog[0].push('k');
    trainLog[0].push('');
    for(let ai = 1, al=alpha.length; ai <= al; ai++){
      trainLog[0].push(String.raw`\alpha_${ai}`);
    }
    trainLog[0].push('b');

    trainLog.push([]);
    trainLog[1].push(`${count}`);
    trainLog[1].push('');
    for(let ai = 0, al=alpha.length; ai < al; ai++){
      trainLog[1].push(String.raw`${alpha[ai].toFixed(2)}`);
    }
    trainLog[1].push(`${b}`);

    while(!isDone){
      isDone = true;
      for(var i=0, il=Tx.length; i < il; i++){
        var sum = 0;
        for(var j=0, jl=Tx.length; j < jl; j++){
          sum += alpha[j]*Ty[j]*G[j][i];
        }
        const rst = Ty[i]*(sum+b);
        if(rst <= 0){
          count++;
          alpha[i] = alpha[i] + eta;
          b = b + eta * Ty[i];
          isDone = false;

          // 保存训练日志
          trainLog.push([]);
          trainLog[count + 1].push(`${count}`);
          trainLog[count + 1].push(`x_${i+1}`);
          for(let ai = 0, al=alpha.length; ai < al; ai++){
            trainLog[count + 1].push(String.raw`${alpha[ai].toFixed(2)}`);
          }
          trainLog[count + 1].push(`${b}`);
        }
      }
    }
    
    this.model.alpha = alpha;
    this.model.b     = b;
    let w = new Vector(2, true);
    // 计算w, b
    for(let ai = 0, al=alpha.length; ai < al; ai++){
      w = w.add(Tx[ai].multiply(alpha[ai]*Ty[ai]));
    }
    
    this.model.w = w;

    this.print();
    if(this.domTable) this.domTable.innerHTML = '';
    showMathStringInTable(this.domTable, trainLog, true);
  }

}

export default DualFormPerceptron;